/*********************************************
 *  CPG Dragonfly™ CMS
 *********************************************
	Copyright © since 2010 by CPG-Nuke Dev Team
	http://dragonflycms.org

	Dragonfly is released under the terms and conditions
	of the GNU GPL version 2 or any later version

	@import "poodle"

	IE 5 - 9 only accepts drag & drop on link, image and text nodes
	http://msdn.microsoft.com/library/hh673546.aspx#Drag_and_Drop_APIs
	This file simulates HTML5 DnD on any node
	Keep in mind that the implementation is not 100% the same
*/

if (Poodle.UA.ie && 10>Poodle.UA.ie) (function(K){

var evt, srect, snode, fnode, cnode, dragging, dt_data=[],
// Simulate http://dev.w3.org/html5/spec/dnd.html#the-datatransfer-interface
dt = {
	dropEffect:    'none', // none / copy / link / move
	effectAllowed: 'uninitialized', // none / copy / copyLink / copyMove / link / linkMove / move / all / uninitialized
//	items : null,
	setDragImage: function(image, x, y){},
	addElement: function(element){},
	types: [],
	getData: function(format){return dt_data[format];},
	setData: function(format, data){
		dt_data[format] = data;
		if (0>this.types.indexOf(format))
			this.types.push(format);
	},
	clearData: function(format){
		if (format) {
			delete dt_data[format];
			var i = this.types.indexOf(format);
			if (-1<i) delete this.types[i];
		} else {
			dt_data = [];
			this.types = [];
		}
	},
	files: null
},
// Point 4 of: http://dev.w3.org/html5/spec/dnd.html#the-dragevent-interface
allowedEffects = {
copy: ["uninitialized", "copy", "copyLink", "copyMove", "all"],
link: ["uninitialized", "link", "copyLink", "linkMove", "all"],
move: ["uninitialized", "move", "copyMove", "linkMove", "all"]
};

function triggerDragEvent(e, name, node)
{
	if (dragging) {
		node = node||e.target;
		// DragEvent interface = MouseEvent + dataTransfer
		evt = document.createEvent('DragEvent');
		evt.initDragEvent(name, 1, 1, e.view, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, node, dt);
		if ('dragover' == name) {
			dt.dropEffect = 'none';
		}
		node.dispatchEvent(evt);
		dt = evt.dataTransfer;
	}
}

function cloneNode(node)
{
	var i=-1,
	    s=node,
	    n=node=s.cloneNode(true),
	cnodes = n.$Q('*'),
	snodes = s.$Q('*');

	while (n && s) {
		var p, style = window.getComputedStyle(s, null), cstyle = s.currentStyle;
		if (cstyle) {
			style = '';
			for (p in cstyle) { style += p + ":" + cstyle[p] + ";"; }
		} else {
			style = style.cssText;
		}
		n.style.cssText = style;
		n = cnodes[++i];
		s = snodes[i];
	}
	return node;
}

function mouseMove(e)
{
	if (snode) {
		if (dragging) {
			/**
			 * TODO:
			 * User agents must, as soon as the drag operation is initiated and
			 * every 350ms (±200ms) thereafter for as long as the drag operation
			 * is ongoing, queue a task to perform steps in sequence
			 * http://dev.w3.org/html5/spec/dnd.html#drag-and-drop-processing-model
			 */
			var n = e.target;
			// prevent feedback element (cloned node) being the target
			if (n == cnode) {
				cnode.style.display="none";
				n = document.elementFromPoint(e.clientX,e.clientY);
				cnode.style.display="";
			}
			// reposition clone
			cnode.setCSS({
				'top':(e.clientY+5)+'px',
				'left':(e.clientX+5)+'px'
			});
			// trigger drag event on source node
			triggerDragEvent(e,'drag', snode);
			// entering/leaving target?
			if (fnode!=e.target) {
				triggerDragEvent(e,'dragleave',fnode);
				triggerDragEvent(e,'dragenter',n);
				fnode = e.target;
			}
			// finally trigger dragover
			triggerDragEvent(e,'dragover', n);
		}
		else if (dragging = (5 < Math.abs(srect.x-e.clientX) || 5 < Math.abs(srect.y-e.clientY)))
		{
			triggerDragEvent(e,'dragstart',snode);
			// only drag when setData() is used
			dragging = ('none'!=dt.effectAllowed && dt.types && dt.types.length);
			if (dragging) {
				cnode = K.$B().$A(cloneNode(snode)).setCSS({
					'position':'absolute',
					'top':(e.clientY+5)+'px',
					'left':(e.clientX+5)+'px',
					'max-width':snode.getWidth()+'px'
				}).addClass('drag-feedback');
				K.$B().addClass('grabbing');
			} else {
				stopDrag(e);
			}
		}
		e.stop();
	}
}

function stopDrag(e)
{
	if (snode) {
		if (dragging) {
			K.$B().removeClass('grabbing');
			if (cnode) cnode.remove();
			var a = allowedEffects[dt.dropEffect];
			if (a && -1<a.indexOf(dt.effectAllowed)) {
				triggerDragEvent(e,'drop');
			}
			triggerDragEvent(e,'dragend',snode);
			dt.clearData();
		}
		dragging = snode = cnode = null;
	}
}

Poodle_initDraggable = function(node)
{
	node.bind('mousedown', function(e){
		if (!snode) {
			snode = fnode = this;
			srect = new PoodlePoint(e.clientX, e.clientY);
		}
	});
};

K.onDOMReady(function(){
	// bind dragstart and dragend to document so that
	// we know the dragged node for 99%
	document
		.bind('dragstart', K.dragStart)
		.bind('dragend',   K.dragEnd)
		.bind('mousemove', mouseMove)
		.bind('mouseup',   stopDrag);
});

// Here we try to support any dataTransfer object on IE8 and IE9
var o = window.Event.prototype,
  opd = Object.getOwnPropertyDescriptor(o, 'dataTransfer');
if (opd && opd.get) {
	Object.defineProperty(o, 'dataTransfer', {
		get:function(){return opd.get.call(this) || this._ie_dt;},
		set:function(v){this._ie_dt=v;}
	});
}

})(Poodle);
